package com.example.filter;

import com.example.common.ApiResult;
import com.example.util.JwtUtils;
import com.example.service.OnlineUserTrackerService;
import com.example.service.TokenStoreService;
import org.springframework.beans.factory.ObjectProvider;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

/**
 * JWT认证过滤器
 * 拦截需要认证的请求，验证JWT Token的有效性
 */
@Component
@Order(1)  // 设置过滤器执行顺序
public class JwtAuthenticationFilter implements Filter {

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private ObjectProvider<OnlineUserTrackerService> onlineUserTrackerProvider;

    @Autowired
    private ObjectProvider<TokenStoreService> tokenStoreProvider;

    // 不需要认证的接口路径（白名单）
    private static final List<String> EXCLUDED_PATHS = Arrays.asList(
        "/api/admin/login",           // 登录接口
        "/api/analysis",              // 在线人数统计接口
        "/api/demo",                  // 演示接口（学习用）
        "/api/sms/send",              // 发送短信验证码接口
        "/api/request",               // 演示接收请求参数接口
        "/api/admin/master-slave",    // 主从库测试接口
        "/swagger-ui",                // Swagger文档
        "/v3/api-docs",               // OpenAPI文档
        "/swagger-resources",         // Swagger资源
        "/webjars",                   // WebJars静态资源
        "/favicon.ico",               // 网站图标
        "/actuator"                   // 监控端点（如果启用）
    );

    // 不需要认证的特定方法和路径组合
    private boolean isExcludedMethodAndPath(String method, String requestPath) {
        // POST /api/admin - 注册管理员接口，允许公开访问
        if ("POST".equals(method) && "/api/admin".equals(requestPath)) {
            return true;
        }
        return false;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 过滤器初始化
        System.out.println("JWT认证过滤器已初始化");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        
        // 获取HTTP请求对象
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        
        // 提取请求信息
        String requestPath = httpRequest.getRequestURI();
        String method = httpRequest.getMethod();
        
        System.out.printf("=== JWT过滤器 === %s %s%n", method, requestPath);
        
        // 检查是否是白名单路径
        if (isExcludedPath(requestPath)) {
            System.out.println("白名单路径，跳过认证: " + requestPath);
            chain.doFilter(request, response);
            return;
        }

        // 检查是否是特定方法和路径的组合（如注册接口）
        if (isExcludedMethodAndPath(method, requestPath)) {
            System.out.println("白名单方法+路径，跳过认证: " + method + " " + requestPath);
            chain.doFilter(request, response);
            return;
        }
        
        // 获取Authorization头
        String authHeader = httpRequest.getHeader("Authorization");
        
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            System.out.println("缺少Authorization头或格式错误");
            sendUnauthorizedResponse(httpResponse, "缺少认证令牌");
            return;
        }
        
        // 提取Token（去掉"Bearer "前缀）
        String token = authHeader.substring(7);
        
        try {
            // 验证Token
            if (jwtUtils.isTokenValid(token)) {
                // Token有效，记录日志即可
                String username = jwtUtils.getUsernameFromToken(token);
                Long userId = jwtUtils.getUserIdFromToken(token);
                System.out.println("Token验证成功，用户: " + username);
                onlineUserTrackerProvider.ifAvailable(tracker -> tracker.refreshOnline(userId, username));

                // 如启用Redis（存在TokenStore Bean），需校验Redis中缓存的token是否存在且匹配
                TokenStoreService tokenStore = tokenStoreProvider.getIfAvailable();
                if (tokenStore != null) {
                    String cached = tokenStore.getToken(userId);
                    if (cached == null || !token.equals(cached)) {
                        sendUnauthorizedResponse(httpResponse, "认证令牌已失效，请重新登录");
                        return;
                    }
                }
                
                // 继续执行后续过滤器和目标方法
                chain.doFilter(request, response);
            } else {
                System.out.println("Token验证失败");
                sendUnauthorizedResponse(httpResponse, "认证令牌无效");
            }
        } catch (Exception e) {
            System.out.println("Token解析异常: " + e.getMessage());
            sendUnauthorizedResponse(httpResponse, "认证令牌格式错误");
        }
    }
    
    /**
     * 检查请求路径是否在白名单中
     */
    private boolean isExcludedPath(String requestPath) {
        return EXCLUDED_PATHS.stream().anyMatch(requestPath::startsWith);
    }
    
    /**
     * 发送未授权响应
     */
    private void sendUnauthorizedResponse(HttpServletResponse response, String message) 
            throws IOException {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setContentType("application/json;charset=UTF-8");
        
        ApiResult<Object> result = ApiResult.unauthorized(message);
        ObjectMapper mapper = new ObjectMapper();
        String jsonResponse = mapper.writeValueAsString(result);
        
        response.getWriter().write(jsonResponse);
        response.getWriter().flush();
    }

    @Override
    public void destroy() {
        // 过滤器销毁
        System.out.println("JWT认证过滤器已销毁");
    }
}
